package cn.com.generaldata.os.service.indicator_evaluation.industry_association_analysis;

import java.math.BigDecimal;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Criteria;
import org.nutz.lang.random.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.generaldata.jsme_indicator_system.entity.IndicatorEvaluation;
import cn.com.generaldata.os.pojo.IndicatorAssociateResult;
import cn.com.generaldata.os.service.indicator_constant.ProvinceIndicatorConstant;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateService;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateServiceHelper;
import cn.com.generaldata.os.vo.IndicatorAccountVO;

/**
 * 基于灰色关联模型的海洋产业关联分析类.
 */
public class GreyInstrucAssociateAnalysisCalculateService implements CalculateService {
	// 渔业增加值
	private final String FishAddName = ProvinceIndicatorConstant.FISHERY_ADDVALUE_NAME;
	// 盐业增加值
	private final String SaltAddName = ProvinceIndicatorConstant.SALT_ADDVALUE_NAME;
	// 船舶工业增加值
	private final String MSIAddName = ProvinceIndicatorConstant.MSI_ADDVALUE_NAME;
	// 化工业增加值
	private final String MCIAddName = ProvinceIndicatorConstant.MCI_ADDVALUE_NAME;
	// 生物医药业增加值
	private final String MBIAddName = ProvinceIndicatorConstant.MBI_ADDVALUE_NAME;
	// 工程建筑业增加值
	private final String MEAIAddName = ProvinceIndicatorConstant.MEAI_ADDVALUE_NAME;
	// 电力业增加值
	private final String MEPIAddName = ProvinceIndicatorConstant.MEPI_ADDVALUE_NAME;
	// 海水利用业增加值
	private final String MSUIAddName = ProvinceIndicatorConstant.MSUI_ADDVALUE_NAME;
	// 交通运输业增加值
	private final String MCTIAddName = ProvinceIndicatorConstant.MCTI_ADDVALUE_NAME;
	// 滨海旅游业增加值
	private final String CoastalTourAddName = ProvinceIndicatorConstant.COASTAL_TOUR_ADDVALUE_NAME;
	private final String[] industrys = new String[] { FishAddName, SaltAddName, MSIAddName, MCIAddName, MBIAddName,
			MEAIAddName, MEPIAddName, MSUIAddName, MCTIAddName, CoastalTourAddName };
	private final String[] industryCode = new String[] { "01", "04", "05", "06", "07", "08", "09", "10", "11", "12" };

	private final Logger logger = LoggerFactory.getLogger(getClass());

	private Dao dao;

	private Dao indicatorSystemDao;

	private CalculateServiceHelper helper;

	// 计算指标方法
	@Override
	public void calculateIndicator(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO) {

		// 基定年份
		int fixBaseYear = indicatorAccountVO.getYear() - 1;
		// 当前年
		int fixYear = indicatorAccountVO.getYear();

		// 原始各产业每年增量
		Double[][] industryAddValues = new Double[industrys.length][fixYear - fixBaseYear + 1];

		// 各产业增量
		for (int i = 0; i < industrys.length; i++) {
			// 取每年的
			for (int j = 0; j <= fixYear - fixBaseYear; j++) {
				Double inputOrAccountingIndicatorValue = helper.getInputOrAccountingIndicatorValue(indicatorAccountVO,
						fixBaseYear + j, industrys[i]);
				if (inputOrAccountingIndicatorValue == null) {
					inputOrAccountingIndicatorValue = 0d;
				}
				industryAddValues[i][j] = inputOrAccountingIndicatorValue;
			}
		}

		for (int i = 0; i < industrys.length; i++) {
			// 某产业与其他产业的原始关联度
			Double[][] associateValue = getAssociateValue(i, fixYear - fixBaseYear, industryAddValues);
			// 某产业与其他产业的套入公式关联度
			Double[][] formulaAssociate = getFormulaAssociate(i, fixYear - fixBaseYear, associateValue);
			// 分产业
			for (int num = 0; num < formulaAssociate.length; num++) {
				if (i == num)
				// 这里是存一个自己对自己关联度为1还是直接跳过？
				{
					IndicatorAssociateResult ier = new IndicatorAssociateResult();
					ier.setAssCode(industryCode[num]);
					ier.setIndicatorId(indicator.getId());
					ier.setSelfCode(industryCode[i]);
					ier.setIndicatorValue(Double.valueOf(1));
					ier.setYear(fixYear);
					ier.setAreaId(indicatorAccountVO.getAreaId());
					Criteria cri = getIndicatorAccountingDataCri(ier);
					Record record = dao.fetch("tbl_indicator_associate_result", cri);
					if (record != null) {
						dao.clear("tbl_indicator_associate_result", cri);
					}
					saveIndicatorEvaluationResult(ier);
					continue;
				}
				Double[] iS = formulaAssociate[num];
				Double sum = new Double(0);
				// 分年份
				for (Double element : iS) {
					if (element != null) {
						sum += element;
					}
				}
				//
				// 最终关联度平均值
				Double average = sum / (fixYear - fixBaseYear + 1);
				BigDecimal bg = new BigDecimal(average);
				average = bg.setScale(10, BigDecimal.ROUND_HALF_UP).doubleValue();
				IndicatorAssociateResult ier = new IndicatorAssociateResult();
				ier.setAssCode(industryCode[num]);
				ier.setIndicatorId(indicator.getId());
				ier.setSelfCode(industryCode[i]);
				ier.setIndicatorValue(average);
				ier.setYear(fixYear);
				ier.setAreaId(indicatorAccountVO.getAreaId());
				Criteria cri = getIndicatorAccountingDataCri(ier);

				Record record = dao.fetch("tbl_indicator_associate_result", cri);
				if (record != null) {
					dao.clear("tbl_indicator_associate_result", cri);
				}

				saveIndicatorEvaluationResult(ier);
			}
		}

	}

	private void saveIndicatorEvaluationResult(IndicatorAssociateResult ier) {
		// 保存新记录
		Chain chain = Chain.make("id", R.UU16());
		chain.add("indicator_id", ier.getIndicatorId());
		chain.add("area_id", ier.getAreaId());
		chain.add("self_code", ier.getSelfCode());
		chain.add("ass_code", ier.getAssCode());
		chain.add("year", ier.getYear());

		chain.add("indicator_value", ier.getIndicatorValue());

		dao.insert("tbl_indicator_associate_result", chain);
	}

	private Criteria getIndicatorAccountingDataCri(IndicatorAssociateResult indicatorAccountVO) {
		Criteria cri = Cnd.cri();
		cri.where().and("indicator_id", "=", indicatorAccountVO.getIndicatorId());
		cri.where().and("self_code", "=", indicatorAccountVO.getSelfCode());
		cri.where().and("ass_code", "=", indicatorAccountVO.getAssCode());
		cri.where().and("area_id", "=", indicatorAccountVO.getAreaId());
		cri.where().and("year", "=", indicatorAccountVO.getYear());
		return cri;
	}

	@Override
	public void setDao(Dao dao) {
		this.dao = dao;
	}

	@Override
	public void setIndicatorSystemDao(Dao indicatorSystemDao) {
		this.indicatorSystemDao = indicatorSystemDao;
	}

	// 计算各产业原始关联度
	private Double[][] getAssociateValue(int industryNum, int total, Double[][] industryAddValues) {
		Double[][] industryAssociates = new Double[industrys.length][total + 1];

		for (int i = 0; i < industrys.length; i++) {
			if (i == industryNum) {
				continue;
			}
			for (int j = 0; j <= total; j++) {
				industryAssociates[i][j] = Math.abs(industryAddValues[industryNum][j] - industryAddValues[i][j]);
			}
		}
		return industryAssociates;
	}

	// 套入公式关联度
	private Double[][] getFormulaAssociate(int industryNum, int total, Double[][] industryAddValues) {
		Double[][] industryAssociates = new Double[industrys.length][total + 1];

		Double maxValue = industryAssociates[0][0];
		Double minValue = industryAssociates[0][0];
		for (Double[] iS : industryAddValues) {
			for (Double element : iS) {
				if (element != null) {
					if (maxValue == null) {
						maxValue = element;
					}
					if (minValue == null) {
						minValue = element;
					}
					if (element > maxValue) {
						maxValue = element;
					}
					if (element < minValue) {
						minValue = element;
					}
				}
			}
		}
		for (int i = 0; i < industrys.length; i++) {
			if (i == industryNum) {
				continue;
			}
			for (int j = 0; j <= total; j++) {
				industryAssociates[i][j] = industryAddValues[i][j] + (0.5 * maxValue) == 0 ? 0
						: (0.5 * maxValue + minValue) / (industryAddValues[i][j] + (0.5 * maxValue));
			}
		}
		return industryAssociates;
	}

	@Override
	public void setCalculateServiceHelper(CalculateServiceHelper calculateServiceHelper) {
		helper = calculateServiceHelper;
	}
}
